/* Filename: parsejsonfile.c
 * Description: 解析json文件，打印
 *  parsejsonfile a.json
 * Last modified: humble 2021-01-14 10:28:41
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <json-c/json.h>


#define getcfgstr(jobj, key, dptr) \
do{\
    json_object *jobjtmp = NULL;\
    if(!json_object_object_get_ex(jobj, key, &jobjtmp)){ fprintf(stderr, "has no %s\n", key); return -1; }\
    const char *tmpptr = json_object_get_string(jobjtmp);\
    if(tmpptr == NULL){ fprintf(stderr, "value of %s is NULL\n", key); return -1; }\
    dptr = strdup(tmpptr);\
    if(dptr == NULL) { fprintf(stderr, "strdup() failed()\n"); return -1; }\
    else { printf("%s:%s\n", key, dptr); }\
}while(0)

#define getcfgint(jobj, key, dvar) \
do{\
    json_object *jobjtmp = NULL;\
    if(!json_object_object_get_ex(jobj, key, &jobjtmp)){ fprintf(stderr, "has no %s\n", key); return -1; }\
    dvar = json_object_get_int(jobjtmp);\
    if(dvar == 0){ fprintf(stderr, "value of %s is 0\n", key); return -1; }\
    else { printf("%s:%d\n", key, dvar); }\
}while(0)

int parse_general(json_object *jobjgeneral)
{
    const char *enablestr = NULL;
    int loglevel = 0;
    getcfgstr(jobjgeneral, "enable", enablestr);
    getcfgint(jobjgeneral, "loglevel", loglevel);
    return 0;
}

int parse_opcua(json_object *jobjopcua)
{
    const char *addr = NULL;
    int port = 0;
    getcfgstr(jobjopcua, "addr", addr);
    getcfgint(jobjopcua, "port", port);
    return 0;
}

int parse_channellist(json_object *jobjchannellist)
{
    const char *tag = NULL;
    int namespace = 0;
    int nodeid = 0;

    uint16_t channellistlen = json_object_array_length(jobjchannellist);
    if(channellistlen <= 0){ fprintf(stderr, "channellistlen:%d\n", channellistlen); return -1; }
    for(int i = 0; i < channellistlen; i++)
    {
        json_object *jobjchannel = json_object_array_get_idx(jobjchannellist, i);
        if(jobjchannel == NULL){ fprintf(stderr, "jobjchannel is NULL\n"); return -1; }
        printf("第%d\n", i);
        getcfgstr(jobjchannel, "tag", tag);
        getcfgint(jobjchannel, "namespace", namespace);
        getcfgint(jobjchannel, "nodeid", nodeid);
    }
    return 0;
}

int main(int argc, char **argv)
{
    int ret = 0;
    if(argc != 2){ fprintf(stderr, "argc != 2"); exit(1); }

    int fd = open(argv[1], O_RDONLY);
    if(fd < 0){ perror("open()"); ret = -1; goto openerr; }

    struct stat statres;
    if(fstat(fd, &statres) < 0){ perror("fstat()"); ret = -1; goto fstaterr; }

    char *str = mmap(NULL, statres.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if(str == MAP_FAILED){ perror("mmap()"); ret = -1; goto mmaperr; }


    enum json_tokener_error error;
    json_object *jobj = NULL;
    jobj = json_tokener_parse_verbose(str, &error);
    if(error != json_tokener_success){
        fprintf(stderr, "json_tokener_parse_verbose() err:%s", json_tokener_error_desc(error));
        ret = -1;
        goto json_tokener_parse_verboseerr;
    }


    json_object *jobjtmp = NULL;

    if(!json_object_object_get_ex(jobj, "general", &jobjtmp)){ fprintf(stderr, "has no general\n"); ret = -1; goto unknownkeyerr; }
    ret = parse_general(jobjtmp);
    if(ret < 0){  goto unknownkeyerr; }

    if(!json_object_object_get_ex(jobj, "opcua", &jobjtmp)){ fprintf(stderr, "has no opcua\n"); ret = -1; goto unknownkeyerr; }
    ret = parse_opcua(jobjtmp);
    if(ret < 0){  goto unknownkeyerr; }

    if(!json_object_object_get_ex(jobj, "channellist", &jobjtmp)){ fprintf(stderr, "has no channellist\n"); ret = -1; goto unknownkeyerr; }
    ret = parse_channellist(jobjtmp);
    if(ret < 0){  goto unknownkeyerr; }


unknownkeyerr:
    json_object_put(jobj);
json_tokener_parse_verboseerr:
    if(munmap(str, statres.st_size) < 0){ perror("munmap()"); ret = -1; }
mmaperr:
fstaterr:
    close(fd);
openerr:
    return ret;
}
